



















if __name__ == '__main__':
    import sys
    sys.path.append('../../')


from quant.markets.markets import Markets, RoutingEngine, data_routing_key
from quant.const import DataFrequency
from quant.utils import EventEngine, data_routing_key, logging


class SimMarkets(Markets):
    def __init__(self):
        super(SimMarkets, self).__init__()
        self.routing_engine = Bridge()
        self.sim_routing_engine = SimDataEngine(self)

    def add_market(self, event, exchange, symbol, frequency=DataFrequency.Normal):
        self.sim_routing_engine.include_market(event, exchange, symbol, strategy=True)

    def feed_raw(self, event, exchange, symbol, frequency, recv_time, raw):
        routing_key = data_routing_key(event, exchange, symbol)
        if routing_key not in self.sim_routing_engine.all_added:
            return

        last = self.now
        if last is not None:
            if recv_time < last or recv_time > last + 60:
                logging.error('feed_raw() data not continuous. delta: {}s'.format(round(recv_time-last, 2)))

        super().feed_raw(event, exchange, symbol, frequency, recv_time, raw)

    def set_push_all(self):
        ee = self.sim_routing_engine
        ee.all_added = EverythingSet()
        ee.strategy_added = EverythingSet()

    def subscribe(self, event, exchange, symbol, handler):
        key = data_routing_key(event, exchange, symbol)
        engine = self.sim_routing_engine.strategy_distributor
        engine.subscribe(key, handler)

    def subscribe_all(self, handler):
        engine = self.sim_routing_engine.strategy_distributor
        engine.subscribe(engine.ALL_DATA, handler)

    def matching_subscribe(self, event, exchange, symbol, handler):
        self.sim_routing_engine.include_market(event, exchange, symbol, matching=True)
        key = data_routing_key(event, exchange, symbol)
        engine = self.sim_routing_engine.matching_distributor
        engine.subscribe(key, handler)

    def matching_subscribe_clock(self, handler):
        self.sim_routing_engine.clock_engine.subscribe('clock', handler)


class SimMarketReal(Markets):
    def __init__(self):
        super().__init__()
        self.clock = EventEngine()

    def feed_raw(self, event, exchange, symbol, frequency, recv_time, raw):
        self.clock.put('clock', recv_time)
        super().feed_raw(event, exchange, symbol, frequency, recv_time, raw)

    def matching_subscribe(self, event, exchange, symbol, handler):
        super().subscribe(event, exchange, symbol, handler)

    def matching_subscribe_clock(self, handler):
        self.clock.subscribe('clock', handler)


class Bridge:
    def __init__(self):
        self.handlers = []

    def push_data(self, routing_key, market_data):
        for handler in self.handlers:
            handler(market_data)

    def subscribe_all(self, handler):
        if handler not in self.handlers:
            self.handlers.append(handler)


class SimDataEngine:
    def __init__(self, markets: Markets):
        self.clock_engine = EventEngine()
        self.strategy_distributor = RoutingEngine()
        self.matching_distributor = RoutingEngine()

        self.strategy_added = set()  # routing_key
        self.matching_added = set()  # routing_key
        self.all_added = set()       # routing_key
        self.has_received = {}       # {routing_key: bool, }

        bridge = markets.routing_engine
        bridge.subscribe_all(self.distribute_market_data)
        markets.timer.register(self._check_no_data, 60)

    def include_market(self, event, exchange, symbol, strategy=False, matching=False):
        routing_key = data_routing_key(event, exchange, symbol)
        self.all_added.add(routing_key)
        self.has_received[routing_key] = False

        if strategy:
            self.strategy_added.add(routing_key)
        if matching:
            self.matching_added.add(routing_key)

    def distribute_market_data(self, market_data):
        routing_key = market_data.routing_key
        self.clock_engine.put('clock', market_data.recv_time)
        self.has_received[routing_key] = True

        if routing_key in self.matching_added:
            self.matching_distributor.push_data(routing_key, market_data)
        if routing_key in self.strategy_added:
            self.strategy_distributor.push_data(routing_key, market_data)

    def _check_no_data(self):
        for key, has_data in self.has_received.items():
            if not has_data:
                logging.error('SimMarket may not have data of {}'.format(key))


class EverythingSet:
    def __contains__(self, item):
        return True

    def add(self, other):
        return


if __name__ == '__main__':
    def try_bridge():
        from quant.utils import set_test_mode, EventEngine
        from quant.accounts import SimAccounts, Order
        from quant.markets.functions import set_quick_mode
        from keys import null_key
        from quant.const import OrderType
        from utils import create_test_env, count_each_book
        set_test_mode()
        set_quick_mode()
        # EventEngine.set_show_mode()

        env = create_test_env('doge-ok-bt-08.24-12.00')
        mar = env.markets
        # mar.set_push_all()

        # mar.add_market('Book', 'Okex', 'doge/usdt.swap')
        # mar.add_market('Book', 'Binance', 'doge/usdt.swap')

        acc = SimAccounts(mar).create_account('Okex', null_key)
        acc.api.place_order(Order('doge/usdt.swap', 'buy', 1.1, 1, order_type=OrderType.PostOnly))

        # mar.add_market('Book', 'Okex', 'doge/usdt.swap')

        # while True:
        #     print('-------------push-------------')
        #     env.replayer.push_one()
        #     input(':')

        env.replayer.start()

    def try_sim_real():
        import sys
        sys.path.append('/root/code')

        from quant.accounts import SimAccounts
        from quant.utils import set_test_mode
        from strategy.settings import read_setting
        from strategy import read_strategy
        from run import build_market_data
        set_test_mode()

        setting = read_setting('fair_maker2_bnsw')

        setting.strategy_id = 'sim_bn_btc_usdt_0'
        setting.run_service = True

        symbol = 'btc/usdt.swap'
        setting.symbol = symbol
        setting.pricing_param['symbol'] = symbol
        build_market_data(setting, symbol)

        markets = SimMarketReal()
        accounts = SimAccounts(markets)
        accounts.set_latency(20)
        # accounts.set_balance({'usdt': {'free': 20000, 'frozen': 0}})

        setting.place_spread = [1,    2,    3]
        setting.place_values = [1000, 1000,  1000]
        setting.place_ignore = [5000, 10000, 15000]

        strategy = read_strategy('FairMaker2')
        strategy = strategy(markets, accounts, setting)
        strategy.start()

        strategy.account.info_engine.show_problems()
        # strategy.account.info_engine.show_deal()
        # strategy.account.info_engine.show_user_data()

        while True:
            input(':')

    def try_sim():
        import sys
        import time
        sys.path.append('/root/code')

        from quant.accounts import SimAccounts
        from quant.utils import set_test_mode, FileRawLogger, RawReplayer
        from quant.markets.functions import set_quick_mode
        from strategy.settings import read_setting
        from strategy import read_strategy
        from run import build_market_data

        set_test_mode()

        setting = read_setting('fair_maker2_bnsw')

        setting.strategy_id = 'sim_bn_gala_swap_11'
        setting.run_service = True

        symbol = 'gala/usdt.swap'
        setting.symbol = symbol
        setting.pricing_param['symbol'] = symbol
        build_market_data(setting, symbol)

        markets = SimMarkets()
        accounts = SimAccounts(markets)
        accounts.set_latency(20)
        # accounts.set_balance({'usdt': {'free': 20000, 'frozen': 0}})

        setting.place_spread = [1,    2,    3]
        setting.place_values = [1000, 1000,  1000]
        setting.place_ignore = [5000, 10000, 15000]

        strategy = read_strategy('FairMaker2')
        strategy = strategy(markets, accounts, setting)
        strategy.start()

        strategy.account.info_engine.show_problems()
        strategy.account.info_engine.show_deal()
        # strategy.account.info_engine.show_user_data()

        logger = FileRawLogger('gala-2bt-12.01', '/root/raw')
        replayer = RawReplayer(markets, logger)

        while True:
            replayer.push_interval(1)
            time.sleep(0.1)

    def try_sim_spot():
        import sys
        import time
        sys.path.append('/root/code')

        from quant.accounts import SimAccounts
        from quant.utils import set_test_mode, FileRawLogger, RawReplayer
        from quant.markets.functions import set_quick_mode
        from strategy.settings import read_setting
        from strategy import read_strategy
        from run import build_market_data

        set_test_mode()

        setting = read_setting('fair_maker2_bn')

        setting.strategy_id = 'sim_bn_gala_spot_a1'
        setting.run_service = True

        symbol = 'gala/usdt'
        setting.symbol = symbol
        setting.pricing_param['symbol'] = symbol
        build_market_data(setting, symbol)

        markets = SimMarkets()
        accounts = SimAccounts(markets)
        accounts.set_latency(20)
        accounts.set_balance({'usdt': {'free': 20000, 'frozen': 0}})

        setting.place_spread = [1,    2,    3]
        setting.place_values = [1000, 1000,  1000]
        setting.place_ignore = [5000, 10000, 15000]

        strategy = read_strategy('FairMaker2')
        strategy = strategy(markets, accounts, setting)
        strategy.start()

        strategy.account.info_engine.show_problems()
        strategy.account.info_engine.show_deal()
        # strategy.account.info_engine.show_user_data()

        logger = FileRawLogger('gala-2bt-12.01', '/root/raw')
        replayer = RawReplayer(markets, logger)

        while True:
            replayer.push_interval(1)
            time.sleep(0.1)

    try_sim_spot()




















